package core.reports;

import java.io.IOException;
import java.io.File;
import java.io.FileOutputStream;

import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

/**
 * This implementation of IReportVisitor saves the table in PDF format.
 * @author Royce
 *
 */
public class PDFBuilder implements IReportBuilder {

	private int numCols;
	private int curCol;
	private int curRow;
	private final int SPACING_PX = 10;
	private final int PADDING_CELL = 3;
	private final int SIZE_NORMAL = 8;
	private final int SIZE_SUBHEADING = 12;
	private final int SIZE_HEADING = 16;
	private final int TABLE_WIDTH_PERCENT = 100;
	
	private final FontFamily STD_FONT = FontFamily.TIMES_ROMAN;
	
	private boolean fileOpen;
	private boolean tableOpen;
	
	private Document document;
	private PdfPTable curTable;
	
	private String _fileName;
	
	/**
	 * Default no-arg constructor
	 */
	private PDFBuilder() {
		fileOpen = false;
		tableOpen = false;
		numCols = -1;
		curCol = 0;
		curRow = 0;
		_fileName = "";
		document = null;
	}
	
	public PDFBuilder(String fileName, String title) throws IOException {
		this();
		openFile(fileName, title);
	}
	
	@SuppressWarnings("unused")
	@Override
	public void openFile(String fileName, String title) throws IOException {
		try {
			document = new Document();
			PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(fileName));
			document.open();
			fileOpen = true;
			_fileName = fileName;
			Paragraph heading = new Paragraph();
			heading.setAlignment(Paragraph.ALIGN_CENTER);
			Font headingFont = new Font(STD_FONT, SIZE_HEADING, Font.BOLD);
			heading.setFont(headingFont);
			heading.setSpacingAfter(SPACING_PX);
			heading.add(new Chunk(title));
			heading.add(new Chunk(""));
			document.add(heading);
		}
		catch (DocumentException e) {
			throw new IOException("DocumentException: " + e.getMessage());
		}
	}

	@Override
	public void startTable(String title, int cols) throws IOException {
		if(!fileOpen) throw new IOException("PDFBuilder: No file open.");
		assert(cols > 0);
		
		try {
			if (tableOpen) {
				//add the currently running table, if it exists.
				completeRow();
				document.add(curTable);
				curTable = null;
			}
			
			if (!title.isEmpty()) {
				Paragraph subHeading = new Paragraph();
				Font subFont = new Font(STD_FONT, SIZE_SUBHEADING, Font.BOLD);
				subHeading.setFont(subFont);
				subHeading.add(new Chunk(title));
				subHeading.setSpacingBefore(SPACING_PX);
				subHeading.setSpacingAfter(SPACING_PX);
				document.add(subHeading);
			}
			
			curTable = new PdfPTable(cols);
			curTable.setWidthPercentage(TABLE_WIDTH_PERCENT);
			tableOpen = true;
			curCol = 0;
			curRow = 0;
			numCols = cols;
			
		}
		catch (DocumentException e) {
			throw new IOException("DocumentException: " + e.getMessage());
		}

	}

	@Override
	public void addCell(Object o) throws IOException {
		if(!fileOpen || !tableOpen)
			throw new IOException("PDFBuilder: No table started.");
		
		Phrase p = new Phrase();
		if (curRow == 0) {
			p.setFont(new Font(STD_FONT, SIZE_NORMAL, Font.BOLD));
		}
		else {
			p.setFont(new Font(STD_FONT, SIZE_NORMAL));
		}
		p.add(o.toString());
		
		PdfPCell cell = new PdfPCell(p);
		cell.setPadding(PADDING_CELL);
		cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
		curTable.addCell(cell);
		
		curCol++;
		if (curCol == numCols) {
			curCol = 0;
			curRow++;
		}

	}

	@Override
	public void completeRow() {
		if (curTable != null) {
			curTable.completeRow();
			curCol = 0;
			curRow++;
		}
	}

	@Override
	public void print() throws IOException {
		if(!fileOpen) return;
		
		try {
			if (tableOpen) {
				completeRow();
			}
			if(curTable != null) document.add(curTable);
			document.close();
			document = null;
			fileOpen = false;
			tableOpen = false;
			java.awt.Desktop.getDesktop().open(new File(_fileName));
			_fileName = "";
		}
		catch (DocumentException e) {
			throw new IOException("DocumentException: " + e.getMessage());
		}

	}

	@Override
	public void addParagraph(String s, boolean isSubheader) throws IOException {
		if(!fileOpen) throw new IOException("PDFBuilder: No file open.");
		if(s.isEmpty())
			printSpacing();
		
		Paragraph p = new Paragraph();
		Font pFont = null;
		if (isSubheader) {
			pFont = new Font(STD_FONT, SIZE_SUBHEADING, Font.BOLD);
		}
		else {
			pFont = new Font(STD_FONT, SIZE_NORMAL);
		}
		p.setFont(pFont);
		//p.setSpacingBefore(SPACING_PX);
		//p.setSpacingAfter(SPACING_PX);
		p.add(new Chunk(s));
		try {
			document.add(p);
		} 
		catch (DocumentException e) {
			e.printStackTrace();
			throw new IOException("DocumentException: " + e.getMessage());
		}
		
	}
	
	private void printSpacing() throws IOException {
		Paragraph p = new Paragraph();
		p.setSpacingBefore(SPACING_PX);
		p.add(new Chunk(""));
		try {
			document.add(p);
		} 
		catch (DocumentException e) {
			e.printStackTrace();
			throw new IOException("DocumentException: " + e.getMessage());
		}
	}

}
